package com.zsjt.app.config;
import com.zsjt.app.compoent.security.permission.AccessDeniedFilter;
import com.zsjt.app.compoent.security.authorized.UserLoginAuthenticationFailureHandler;
import com.zsjt.app.compoent.security.authorized.UserLoginAuthenticationSuccessHandler;
import com.zsjt.app.compoent.security.authorized.UserLogoutAuthenticationSuccessHandler;
import com.zsjt.app.compoent.security.session.InvalidSessionStrategyImpl;
import com.zsjt.app.compoent.security.session.SessionInformationExpiredStrategyImpl;
import com.zsjt.app.compoent.utils.common.MD5Util;
import com.zsjt.app.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
 * WebSecurityConfigurerAdapter 配置类
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) //可以使用@secure，@prePost
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    private UserLoginAuthenticationSuccessHandler userLoginAuthenticationSuccessHandler;//认证成功的处理类

    private UserLoginAuthenticationFailureHandler userLoginAuthenticationFailureHandler;//认证失败的处理类

    private UserLogoutAuthenticationSuccessHandler userLogoutAuthenticationSuccessHandler;//用户退出成功处理类

    private AccessDeniedFilter accessDeniedFilter; //拦截权限处理类

    private InvalidSessionStrategyImpl invalidSessionStrategy; //session无效处理类

    private SessionInformationExpiredStrategyImpl sessionInformationExpiredStrategy; //  其他地方登录session失效处理类

    @Autowired
    public void setUserLoginAuthenticationFailureHandler(UserLoginAuthenticationFailureHandler userLoginAuthenticationFailureHandler) {
        this.userLoginAuthenticationFailureHandler = userLoginAuthenticationFailureHandler;
    }
    @Autowired
    public void setUserLoginAuthenticationSuccessHandler(UserLoginAuthenticationSuccessHandler userLoginAuthenticationSuccessHandler) {
        this.userLoginAuthenticationSuccessHandler = userLoginAuthenticationSuccessHandler;
    }

    @Autowired
    public void setUserLogoutAuthenticationSuccessHandler(UserLogoutAuthenticationSuccessHandler userLogoutAuthenticationSuccessHandler) {
        this.userLogoutAuthenticationSuccessHandler = userLogoutAuthenticationSuccessHandler;
    }

    @Autowired
    public void setAccessDeniedFilter(AccessDeniedFilter accessDeniedFilter) {
        this.accessDeniedFilter = accessDeniedFilter;
    }

    @Autowired
    public void setInvalidSessionStrategy(InvalidSessionStrategyImpl invalidSessionStrategy) {
        this.invalidSessionStrategy = invalidSessionStrategy;
    }

    @Autowired
    public void setSessionInformationExpiredStrategy(SessionInformationExpiredStrategyImpl sessionInformationExpiredStrategy) {
        this.sessionInformationExpiredStrategy = sessionInformationExpiredStrategy;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
                .disable(); //关闭跨域csrf拦截

        http.sessionManagement()    //会话处理
                //.invalidSessionUrl()
               // .invalidSessionStrategy(invalidSessionStrategy) // 设置session无效处理策略
                .maximumSessions(1)  // 设置同一个用户只能有一个登陆session
                .maxSessionsPreventsLogin(false) // 当达到maximumSessions时，true表示不能踢掉前面的登录，false表示踢掉前面的用户
               // .expiredUrl()
                .expiredSessionStrategy(sessionInformationExpiredStrategy);  // 其他地方登录session失效处理策略

        http.authorizeRequests()
//                .antMatchers("/system/management/**").hasAnyAuthority("VIP1") //定制请求的授权规则
//                .antMatchers("/system/monitor/**").hasAnyAuthority("VIP2") "/images/**","/test"
                .antMatchers("/login","/asserts/**","/js/**",
                        "/webjars/**","/lossPassword",
                "/userIsAccountExist","/userSendEmailCode","/userUpdatePassword","/userSendPhoneCode","/session/invalid").permitAll() //静态资源可以访问
                .anyRequest().authenticated();

        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedFilter); //自定权限拦截处理

        http.formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginPage("/login") //登陆页面
                .successHandler(userLoginAuthenticationSuccessHandler) //认证成功处理
                .failureHandler(userLoginAuthenticationFailureHandler) //认证失败处理
//                .defaultSuccessUrl("/main.html") //默认登陆成功之后的页面
                .loginProcessingUrl("/userlogin"); //登陆处理的url

        http.rememberMe()  //开启记住我功能
                .rememberMeParameter("rememberPsw"); //登陆成功以后，将cookie发送给浏览器保存，以后登陆带上这个cookie，只要通过检测就可以免登录

        http.logout()
                //.deleteCookies("JSESSIONID","remember-me")//1、访问/lagout 表示用户注销,清空session 删除cookie 开启自动配置的注销功能
                .logoutSuccessHandler(userLogoutAuthenticationSuccessHandler); //2、用户退出成功处理类
              //  .logoutSuccessUrl("/"); // 2、注销成功会返回页面"/"：
    }

    @Override
    @Bean
    public UserDetailsServiceImpl userDetailsService(){
        return new UserDetailsServiceImpl();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService())
                .passwordEncoder(new PasswordEncoder(){
                    @Override
                    public String encode(CharSequence rawPassword) {
                        return MD5Util.encode((String)rawPassword);
                    }
                    @Override
                    public boolean matches(CharSequence rawPassword, String encodedPassword) {
                     //   System.out.println("rawPassword 用户输入的:"+rawPassword);
                     //   System.out.println("encodedPassword 数据库的密码:"+encodedPassword);
                        return encodedPassword.equals(rawPassword);
                        //return encodedPassword.equals(MD5Util.encode((String)rawPassword));
                    }});
    }
}
